/*
 * Funny Language - a free style programming language.
 * Copyright (C) 2015 by fanguangping (fanguangping@163.com)
 *
 */


#include "runner_translate.h"

#define SYS_MACRO_TEXT "$$ \n\
$$ Funny Language - a free style programming language. \n\
$$ Copyright (C) 2014 by fanguangping. Email: fanguangping@163.com \n\
$$ \n\
\n\
$$ example: {define template {or}: {{x} or {y}} as {(or {x} {y})}} \n\
statement: {define template {name}: {template} as {statement}}\n\
name: deftpl\n\
function: FUNCNAME[{statement}]\n\
mapping: {template} > {statement}\n\
run: NIL\n\
eval: NIL\n\
\n\
$$ example: {define {abc} as {123}}\n\
statement: {define {var} as {val}}\n\
name: defvar\n\
function: NIL\n\
mapping: NIL\n\
run: NIL\n\
eval: (define EXTRACT[{var}] MATCH[{val}])\n\
\n\
$$ example: {define function {qsum}: {the sum of squares {a} and {b}} as {{{a}*{a}}+{{b}*{b}}}}\n\
statement: {define function {name}: {function} as {statement}}\n\
name: defun\n\
function: EXTRACT[{name}]\n\
mapping: {function} > \\{(EXTRACT[{name}] TARGET[{function}])\\}\n\
run: NIL\n\
eval: (define (EXTRACT[{name}] ARGLIST[{function}]) MATCH[{statement}])\n"

FILE* __wrap_fopen(const char* filename, const char* modes);

FILE* __wrap_fopen(const char* filename, const char* modes) {
    check_expected(filename);
    check_expected(modes);
    return (FILE*)mock();
}

void test_parse_sys_macro() {
    const char* sys_macro_file_name = "sys.macro";
    const char* sys_macro_modes = "rb";
    FILE* fp = create_temp_file(SYS_MACRO_TEXT);
    rewind(fp);

    expect_string(__wrap_fopen, filename, sys_macro_file_name);
    expect_string(__wrap_fopen, modes, sys_macro_modes);
    will_return(__wrap_fopen, fp);

    parse_sys_macro(sys_macro_file_name);

    Queue * queue = get_mappings(parse("{define template {or}: {{x} or {y}} as {(or {x} {y})}}"));
    assert_non_null(queue);
    assert_int_equal(count_queue_element(queue), 3);
    Mapping *deftpl = dequeue(queue);
    Mapping *defvar = dequeue(queue);
    Mapping *defun = dequeue(queue);

    assert_string_equal(deftpl->source, "{define template {name}: {template} as {statement}}");
    assert_string_equal(deftpl->sys->name, "deftpl");
    assert_string_equal(deftpl->sys->function, "FUNCNAME[{statement}]");
    assert_string_equal(deftpl->sys->mapping, "{template} > {statement}");
    assert_string_equal(deftpl->sys->run, "NIL");
    assert_string_equal(deftpl->sys->eval, "NIL");

    assert_string_equal(defvar->source, "{define {var} as {val}}");
    assert_string_equal(defvar->sys->name, "defvar");
    assert_string_equal(defvar->sys->function, "NIL");
    assert_string_equal(defvar->sys->mapping, "NIL");
    assert_string_equal(defvar->sys->run, "NIL");
    assert_string_equal(defvar->sys->eval, "(define EXTRACT[{var}] MATCH[{val}])");

    assert_string_equal(defun->source, "{define function {name}: {function} as {statement}}");
    assert_string_equal(defun->sys->name, "defun");
    assert_string_equal(defun->sys->function, "EXTRACT[{name}]");
    assert_string_equal(defun->sys->mapping, "{function} > \\{(EXTRACT[{name}] TARGET[{function}])\\}");
    assert_string_equal(defun->sys->run, "NIL");
    assert_string_equal(defun->sys->eval, "(define (EXTRACT[{name}] ARGLIST[{function}]) MATCH[{statement}])");
}


int main(int argc, char **argv) {
    const struct CMUnitTest tests[] = {
            cmocka_unit_test(test_parse_sys_macro),
    };
    return cmocka_run_group_tests(tests, setup_translate, teardown_translate);
}
